package com.atguigu.tingshu.album.service.impl;

import com.atguigu.tingshu.album.mapper.AlbumAttributeValueMapper;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.common.cache.TsCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.lettuce.core.RedisClient;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.Nullable;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

	@Autowired
	private AlbumInfoMapper albumInfoMapper;
    @Autowired
    private AlbumAttributeValueMapper albumAttributeValueMapper;
    @Autowired
    private AlbumStatMapper albumStatMapper;
    @Autowired
    private RabbitService rabbitService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    @TsCache(prefix = "statVo:")
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        return albumInfoMapper.selectAlbumStatVo(albumId);
    }

    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        // 构建查询条件
        LambdaQueryWrapper<AlbumInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AlbumInfo::getUserId,userId);
        wrapper.orderByDesc(AlbumInfo::getId);
        Page<AlbumInfo> albumInfoPage = new Page<>(1,100);
        Page<AlbumInfo> infoPage = albumInfoMapper.selectPage(albumInfoPage,wrapper);
        return infoPage.getRecords();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long albumId) {
        //	删除album_info;
        albumInfoMapper.deleteById(albumId);
        //  删除 album_attribute_value;
        albumAttributeValueMapper.delete(
                new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,albumId));
        //  删除统计信息 album_stat;
        albumStatMapper.delete(
                new LambdaQueryWrapper<AlbumStat>().eq(AlbumStat::getAlbumId,albumId)
        );
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(Long albumId, AlbumInfoVo albumInfoVo) {
        //  update album_info set title = ? where id = ?;
        AlbumInfo albumInfo = new AlbumInfo();
        BeanUtils.copyProperties(albumInfoVo,albumInfo);
        albumInfo.setId(albumId);
        albumInfoMapper.updateById(albumInfo);
        //  album_attribute_value 由于修改值的时候未触发控制器，所以不能实时记录修改的信息。因此要先删除数据，再新增数据！
        //  删除原有标签数据; delete from album_attribute_value where album_id = ?;
        //  物理删除; 因为实体类中有一个isDelete字段 TableLgoic 逻辑删除！
        albumAttributeValueMapper.delete(
                new LambdaQueryWrapper<AlbumAttributeValue>().eq(AlbumAttributeValue::getAlbumId,albumId));
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
            //循环遍历修改
            for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                //船舰修改的实体对象
                AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                //属性拷贝
                BeanUtils.copyProperties(albumAttributeValueVoList,albumAttributeValue);
                albumAttributeValue.setAlbumId(albumId);
                //  insert into album_attribute_value values()
                //  insert into album_attribute_value values()
                //  insert into album_attribute_value values()
                //  insert into album_attribute_value values()
                //  优化为: insert into album_attribute_value values(?,?,?,?,?,?) values(?,?,?,?,?,?) values(?,?,?,?,?,?)
                albumAttributeValueMapper.insert(albumAttributeValue);
            }
        }
        //  判断当前专辑是公开; is_open=1;
        if ("1".equals(albumInfo.getIsOpen())) {
            //  调用上架方法;
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
            // 布隆过滤器
            RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
            //为啥使用id过滤   因为传参  查询使用的是id
            bloomFilter.add(albumInfo.getId());

        } else {
            //  调用下架方法;
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, albumInfo.getId());
        }
    }

    @Override
    @TsCache(prefix = "album:", suffix = ":info")
    public AlbumInfo getAlbumInfo(Long albumId) {
        return this.getAlbumInfoDB(albumId);
//        //定义redis数据类型string
//        String dateKey = RedisConstant.ALBUM_INFO_PREFIX + albumId;
//        try {
//            //根据缓存的key查数据               有概率redis挂了 所以需要try catch
//            AlbumInfo albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(dateKey);
//            //判断缓存是否存在
//            if(null == albumInfo){
//                //不存在查询数据库
//                String lockKey = RedisConstant.ALBUM_LOCK_SUFFIX + albumId;
//                RLock lock = redissonClient.getLock(lockKey);
//                lock.lock();
//                try {
//                    //业务逻辑
//                    albumInfo = getAlbumInfoDB(albumId);
//                    // 判断数据是否为空
//                    if(null == albumInfo){
//                        // 防止穿透 设置空值    bitmap getbit or setbit    布隆过滤器
//                        this.redisTemplate.opsForValue().set(dateKey,new AlbumInfo(),RedisConstant.ALBUM_TEMPORARY_TIMEOUT, TimeUnit.SECONDS);
//                        return new AlbumInfo();
//                    }
//                    //  数据库中有数据
//                    this.redisTemplate.opsForValue().set(dateKey,albumInfo,RedisConstant.ALBUM_TIMEOUT, TimeUnit.SECONDS);
//                    //  返回数据
//                    return albumInfo;
//                } catch (Exception e) {
//                    log.error(e.getMessage(), e);
//                }finally {
//                    //解锁
//                    lock.unlock();
//                }
//            }else {
//                //缓存中有数据 redis
//                System.out.println("缓存有数据");
//                return albumInfo;
//            }
//        } catch (Exception e) {
//            log.error(e.getMessage(), e);
//        }
//        //数据库兜底
//        return getAlbumInfoDB(albumId);
    }

    private @Nullable AlbumInfo getAlbumInfoDB(Long albumId) {
        //  因为需要给专辑标签赋值; albumAttributeValueVoList
        //  查询专辑信息表;
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        //  防止空指针
        if(null!= albumInfo){
            //  根据专辑Id获取到标签数据：
            //  select * from album_attribute_value where album_id = 1630 ;
            //  Warpper 构建查询条件的
            LambdaQueryWrapper<AlbumAttributeValue> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(AlbumAttributeValue::getAlbumId, albumId);
            List<AlbumAttributeValue> albumAttributeValueList = albumAttributeValueMapper.selectList(wrapper);
            albumInfo.setAlbumAttributeValueVoList(albumAttributeValueList);
        }
        return albumInfo;
    }

    @Override
    public IPage<AlbumListVo> findUserAlbumPage(Page<AlbumListVo> page, AlbumInfoQuery albumInfoQuery) {
        return albumInfoMapper.selectUserAlbumPage(page,albumInfoQuery);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
        /*
            album_attribute_value
			album_info
			album_stat
         */

        //1.先保存专辑信息表
        try {
            AlbumInfo albumInfo = new AlbumInfo();
            //属性赋值,前提：属性名一样
            BeanUtils.copyProperties(albumInfoVo,albumInfo);
            //前端传递的数据是否都要保存到数据表或保存到数据表中的数据，前端都传递了没 需要校验！
            //用户id前端没给 获取当前用户id tracks_for_free免费试听集数  status
            albumInfo.setUserId(userId);
            //设置试听集数
            if (!SystemConstant.ALBUM_PAY_TYPE_FREE.equals(albumInfoVo.getPayType())) {
                //付费的
                albumInfo.setTracksForFree(5);
            }
            //	设置审核状态：发送一个消息；给管理平台:站内信（提示信息）审核通过：监听消息完成审核状态赋值!
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
            //表示执行的insert方法
            albumInfoMapper.insert(albumInfo);
            //2.保存标签
            List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
            if (!CollectionUtils.isEmpty(albumAttributeValueVoList)) {
                //循环遍历赋值
                for (AlbumAttributeValueVo albumAttributeValueVo : albumAttributeValueVoList) {
                    //创建对象
                    AlbumAttributeValue albumAttributeValue = new AlbumAttributeValue();
                    //赋值
                    albumAttributeValue.setAlbumId(albumInfo.getId());
                    albumAttributeValue.setAttributeId(albumAttributeValueVo.getAttributeId());
                    albumAttributeValue.setValueId(albumAttributeValueVo.getValueId());
                    //	执行多次insert into album_attribute_value values();
                    //	执行多次insert into album_attribute_value values();
                    //	执行多次insert into album_attribute_value values();
                    //	执行多次insert into album_attribute_value values();
                    albumAttributeValueMapper.insert(albumAttributeValue);
                    // 作业：优化进行批量保存  优化为： 优化为: insert into album_attribute_value values(?,?,?,?,?,?)
                    //                                                               values(?,?,?,?,?,?) values(?,?,?,?,?,?)
                }
            }
            //3.专辑统计表
            saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_PLAY);
            saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_SUBSCRIBE);
            saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_BROWSE);
            saveAlbumStat(albumInfo.getId(),SystemConstant.ALBUM_STAT_COMMENT);

            //  判断当前专辑是公开; is_open=1;
            if ("1".equals(albumInfo.getIsOpen())) {
                //  调用上架方法;
                rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumInfo.getId());
                //布隆过滤器
                RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
                bloomFilter.add(albumInfo.getId());
            }
        } catch (BeansException e) {
            log.error(e.getMessage(),e);
            throw new GuiguException(ResultCodeEnum.SERVICE_ERROR);
        }

        return true;
    }

    public void saveAlbumStat(Long albumid, String statPlay) {
        //创建对象
        AlbumStat albumStat = new AlbumStat();

        albumStat.setAlbumId(albumid);
        albumStat.setStatType(statPlay);
        if("0401".equals(statPlay)){
            albumStat.setStatNum(0);
        }else {
            albumStat.setStatNum(new Random().nextInt(10000));
        }
        albumStatMapper.insert(albumStat);
    }
}
